package com.huqing.icu.service.app.impl;

import com.huqing.icu.base.IdReq;
import com.huqing.icu.base.PagingDto;
import com.huqing.icu.base.redis.annotation.RedisLock;
import com.huqing.icu.client.UserFeignClient;
import com.huqing.icu.constants.CacheLockConstants;
import com.huqing.icu.dao.HouseDao;
import com.huqing.icu.dao.HouseInteractionPanelDao;
import com.huqing.icu.dao.HouseUserActionRecordDao;
import com.huqing.icu.dao.UserViewHouseRecordDao;
import com.huqing.icu.dto.HouseDto;
import com.huqing.icu.dto.HouseQueryDto;
import com.huqing.icu.enums.*;
import com.huqing.icu.exceptions.BusinessException;
import com.huqing.icu.inout.in.app.*;
import com.huqing.icu.inout.out.app.AppHouseListResp;
import com.huqing.icu.inout.resp.user.UserInfoQueryResp;
import com.huqing.icu.model.*;
import com.huqing.icu.service.app.IAppHouseService;
import com.huqing.icu.service.savestrategy.AbstractHouseSaveService;
import com.huqing.icu.service.savestrategy.HouseSaveServiceHandler;
import com.huqing.icu.utils.CopyUtils;
import com.huqing.icu.utils.JsonUtils;
import com.huqing.icu.utils.PageUtils;
import com.huqing.icu.utils.ParamValidateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 房源接口实现类
 *
 * @author huqing
 * @date 2024-09-15 23:13:21
 */
@Service
public class AppHouseServiceImpl implements IAppHouseService {

    private static final Logger logger = LoggerFactory.getLogger(IAppHouseService.class);

    @Autowired
    private HouseSaveServiceHandler houseSaveServiceHandler;

    @Autowired
    private HouseDao houseDao;
    @Autowired
    private UserViewHouseRecordDao userViewHouseRecordDao;
    @Autowired
    private HouseUserActionRecordDao houseUserActionRecordDao;
    @Autowired
    private HouseInteractionPanelDao houseInteractionPanelDao;
    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 新增房源
     *
     * @param houseAddReq
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer insertHouse(HouseAddReq houseAddReq) {

        House house = CopyUtils.copy(houseAddReq, House.class);

        //要检查参数
        //AbstractHouseSaveService houseSaveService = houseSaveServiceHandler.getHouseOwnerInstance(house.getHouseOwner());
        //houseSaveService.checkAddReq(houseAddReq);

        if (CollectionUtils.isNotEmpty(houseAddReq.getImageList())) {
            house.setImageListStr(JsonUtils.obj2String(houseAddReq.getImageList()));
        }
        houseDao.insert(house);

        //3、新增一条待审核的记录
        HouseApproveRecord houseApproveRecord = new HouseApproveRecord();
        houseApproveRecord.setHouseId(house.getId());
        houseDao.insertHouseApproveRecord(houseApproveRecord);

        //4、新增一条互动统计数据（点赞量、收藏量）
        houseInteractionPanelDao.init(house.getId());
        return 1;
    }

    /**
     * 修改房源
     *
     * @param houseUpdateReq
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer updateHouse(HouseUpdateReq houseUpdateReq) {

        //1、查询该房源是否存在
        HouseDto oldHouse = houseDao.selectById(houseUpdateReq.getId());
        if (oldHouse == null) {
            throw new BusinessException(BusinessConstants.DATA_NOT_EXIST.getCode(), "房源不存在，请检查");
        }

        House house = CopyUtils.copy(houseUpdateReq, House.class);

        //2、要检查参数
        AbstractHouseSaveService houseSaveService = houseSaveServiceHandler.getHouseOwnerInstance(house.getHouseOwner());
        //houseSaveService.checkUpdateReq(houseUpdateReq);
        houseDao.updateById(house);

        //3、如果房源不是待审核状态，则需要删除，新增一条待审核记录
        if (!HouseApproveStatusEnum.NOT_APPROVE.getCode().equals(oldHouse.getApproveStatus())) {
            houseDao.deleteApproveRecordByHouseId(houseUpdateReq.getId());
            HouseApproveRecord houseApproveRecord = new HouseApproveRecord();
            houseApproveRecord.setHouseId(houseUpdateReq.getId());
            houseDao.insertHouseApproveRecord(houseApproveRecord);
        }

        return 1;
    }

    /**
     * 房子已经租出去了
     *
     * @param rentOutReq
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer rentOut(RentOutReq rentOutReq) {
        //1、根据房源id和用户id查询房源
        House house = houseDao.selectOneByUserId(rentOutReq.getUserId(), rentOutReq.getHouseId(), DeleteStatusEnum.NOT_DELETED.getCode());

        if (house == null) {
            ParamValidateUtils.throwInternalErrorExp("房源不存在");
        }
        if (IsOrNotEnum.IS.getCode().equals(house.getDownStatus())) {
            ParamValidateUtils.throwInternalErrorExp("房源已经下架，不能修改状态");
        }

        //2、将状态改成已经租出去了
        House newHouse = new House();
        newHouse.setId(house.getId());
        newHouse.setDownStatus(IsOrNotEnum.IS.getCode());
        newHouse.setDownReasonType(rentOutReq.getDownReasonType());
        newHouse.setDownReason(rentOutReq.getDownReason());
        houseDao.updateById(newHouse);

        return 1;
    }

    /**
     * 查询房源列表
     *
     * @param queryReq
     * @return
     */
    @Override
    public PagingDto<AppHouseListResp> queryList(AppHouseListQueryReq queryReq, Long loginUserId) {
        HouseQueryDto houseQueryDto = CopyUtils.copy(queryReq, HouseQueryDto.class);

        //客户端只能查询那些已上架、审核通过、未删除的房子
        houseQueryDto.setDownStatus(HouseDownStatusEnum.UP.getCode());
        houseQueryDto.setQueryApprove(IsOrNotEnum.IS.getCode());
        houseQueryDto.setApproveStatus(HouseApproveStatusEnum.PASS.getCode());
        houseQueryDto.setIsDeleted(DeleteStatusEnum.NOT_DELETED.getCode());

        int startIndex = PageUtils.getPageStartIndex(queryReq.getPageIndex(), queryReq.getPageSize());
        houseQueryDto.setStartIndex(startIndex);


        //2、查询满足条件有多少个
        Integer count = houseDao.getNumByCondition(houseQueryDto);
        if (count == 0) {
            return new PagingDto(Collections.emptyList(), 0, 0);
        }

        //2.2、查询房源列表
        List<HouseDto> houseDtoList = houseDao.selectByCondition(houseQueryDto);

        List<AppHouseListResp> houseRespList = linkHouseData(houseDtoList, loginUserId);
        PagingDto pagingDto = new PagingDto<>(houseRespList, PageUtils.getTotalPage(count, queryReq.getPageSize()), count);
        return pagingDto;
    }

    /**
     * 查询房源详情
     *
     * @param userId
     * @param houseId
     * @return
     */
    @Override
    public AppHouseListResp queryDetail(Long userId, Long houseId) {

        HouseDto houseDto = houseDao.selectById(houseId);
        AppHouseListResp houseListResp = CopyUtils.copy(houseDto, AppHouseListResp.class);

        //浏览数和浏览人数+1
        incrViewCountAndUserCount(userId, houseId);

        //2 查询我是否有点赞和收藏
        if (userId != null) {
            HouseUserActionRecord userLikeAction = houseUserActionRecordDao.selectOneByUserId(userId, houseId, UserActionTypeEnum.LIKE.getCode());
            HouseUserActionRecord userFavoriteAction = houseUserActionRecordDao.selectOneByUserId(userId, houseId, UserActionTypeEnum.FAVORITE.getCode());

            Integer isLike = userLikeAction == null ? IsOrNotEnum.NOT.getCode() : IsOrNotEnum.IS.getCode();
            Integer isFavorite = userFavoriteAction == null ? IsOrNotEnum.NOT.getCode() : IsOrNotEnum.IS.getCode();
            houseListResp.setIsLike(isLike);
            houseListResp.setIsFavorite(isFavorite);

            //查询用户信息
            UserInfoQueryResp userInfo = userFeignClient.getUserById(userId);
            if (userInfo != null) {
                houseListResp.setNickname(userInfo.getNickname());
                houseListResp.setAvatar(userInfo.getAvatar());
            }
        }

        //3.2、查询点赞量、收藏量等
        HouseInteractionPanel houseInteractionPanel = houseInteractionPanelDao.selectByHouseId(houseId);
        if (houseInteractionPanel != null) {
            houseListResp.setActualViewCount(houseInteractionPanel.getActualViewCount());
            houseListResp.setActualViewUserCount(houseInteractionPanel.getActualViewUserCount());
            houseListResp.setActualLikeCount(houseInteractionPanel.getActualLikeCount());
            houseListResp.setActualFavoriteCount(houseInteractionPanel.getActualFavoriteCount());
            houseListResp.setActualCommentCount(houseInteractionPanel.getActualCommentCount());
        }

        if (StringUtils.isNotBlank(houseListResp.getImageListStr())) {
            List<String> imgList = JsonUtils.getList(houseListResp.getImageListStr(), String.class);
            houseListResp.setImgList(imgList);
        }

        return houseListResp;
    }

    /**
     * 查询我发布的房源列表
     *
     * @param loginUserId
     * @return
     */
    @Override
    public PagingDto<AppHouseListResp> queryUserHouse(UserHouseQueryReq queryReq, Long loginUserId) {

        HouseQueryDto houseQueryDto = CopyUtils.copy(queryReq, HouseQueryDto.class);
        //根据ID倒序，新发布的先展示
        houseQueryDto.setSortType(HouseListSortTypeEnum.ID_DESC.getCode());

        //如果当前登录人和要查的用户ID是同一个，说明是自己查看自己的房源，则那些下架的、未审核的都能看到
        //否则，说明是别人在看我的房源，则只能看到我的已上架、审核通过的
        if (!queryReq.getUserId().equals(loginUserId)) {
            houseQueryDto.setDownStatus(HouseDownStatusEnum.UP.getCode());
            houseQueryDto.setQueryApprove(IsOrNotEnum.IS.getCode());
            houseQueryDto.setApproveStatus(HouseApproveStatusEnum.PASS.getCode());
        }
        houseQueryDto.setIsDeleted(DeleteStatusEnum.NOT_DELETED.getCode());

        int startIndex = PageUtils.getPageStartIndex(queryReq.getPageIndex(), queryReq.getPageSize());
        houseQueryDto.setStartIndex(startIndex);


        //2、查询满足条件有多少个
        Integer count = houseDao.getNumByCondition(houseQueryDto);
        if (count == 0) {
            return new PagingDto(Collections.emptyList(), 0, 0);
        }

        //2.2、查询房源列表
        List<HouseDto> houseDtoList = houseDao.selectByCondition(houseQueryDto);

        List<AppHouseListResp> houseRespList = linkHouseData(houseDtoList, loginUserId);
        PagingDto pagingDto = new PagingDto<>(houseRespList, PageUtils.getTotalPage(count, queryReq.getPageSize()), count);
        return pagingDto;
    }

    public List<AppHouseListResp> linkHouseData(List<HouseDto> houseDtoList, Long userId) {

        List<Long> idList = houseDtoList.stream().map(HouseDto::getId).collect(Collectors.toList());

        //3、查询我有没有点赞过、收藏过
        Map<Long, HouseUserActionRecord> userLikeRecordMap = null;
        Map<Long, HouseUserActionRecord> userFavoriteRecordMap = null;
        if (userId != null) {
            List<HouseUserActionRecord> userActionRecordList = houseUserActionRecordDao.selectByUserId(userId, Arrays.asList(UserActionTypeEnum.LIKE.getCode(), UserActionTypeEnum.FAVORITE.getCode()));
            if (CollectionUtils.isNotEmpty(userActionRecordList)) {
                //筛选出点赞过的房源
                List<HouseUserActionRecord> userLikeRecordList = userActionRecordList.stream().filter(o -> UserActionTypeEnum.LIKE.getCode().equals(o.getActionType())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(userActionRecordList)) {
                    userLikeRecordMap = userLikeRecordList.stream().collect(Collectors.toMap(HouseUserActionRecord::getHouseId, p -> p));
                }

                //筛选出收藏过的房源
                List<HouseUserActionRecord> userFavoriteRecordList = userActionRecordList.stream().filter(o -> UserActionTypeEnum.LIKE.getCode().equals(o.getActionType())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(userFavoriteRecordList)) {
                    userFavoriteRecordMap = userLikeRecordList.stream().collect(Collectors.toMap(HouseUserActionRecord::getHouseId, p -> p));
                }
            }
        }

        //3.2、查询点赞量、收藏量等
        Map<Long, HouseInteractionPanel> houseInteractionPanelMap = null;
        List<HouseInteractionPanel> houseInteractionPanelList = houseInteractionPanelDao.selectByHouseIdList(idList);
        if (CollectionUtils.isNotEmpty(houseInteractionPanelList)) {
            houseInteractionPanelMap = houseInteractionPanelList.stream().collect(Collectors.toMap(HouseInteractionPanel::getHouseId, p -> p));
        }

        //3.3、查询用户信息
        Map<Long, UserInfoQueryResp> userInfoMap = null;
        List<Long> userIdList = houseDtoList.stream().map(HouseDto::getUserId).distinct().collect(Collectors.toList());
        List<UserInfoQueryResp> userInfoList = userFeignClient.queryList(new IdReq(userIdList));
        if (CollectionUtils.isNotEmpty(userInfoList)) {
            userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfoQueryResp::getUserId, p -> p));
        }

        List<AppHouseListResp> houseRespList = CopyUtils.copyOriginListToDestList(houseDtoList, AppHouseListResp.class);
        for (AppHouseListResp listResp : houseRespList) {

            if (StringUtils.isNotBlank(listResp.getImageListStr())) {
                List<String> imgList = JsonUtils.getList(listResp.getImageListStr(), String.class);
                listResp.setImgList(imgList);
            }

            //4.1 我是否点赞过
            if (userLikeRecordMap != null && userLikeRecordMap.containsKey(listResp.getId())) {
                listResp.setIsLike(IsOrNotEnum.IS.getCode());
            }

            //4.2 我是否收藏过
            if (userFavoriteRecordMap != null && userFavoriteRecordMap.containsKey(listResp.getId())) {
                listResp.setIsFavorite(IsOrNotEnum.IS.getCode());
            }

            //5、填充用户信息
            if (userInfoMap != null && userInfoMap.containsKey(listResp.getUserId())) {
                UserInfoQueryResp userInfo = userInfoMap.get(listResp.getUserId());
                listResp.setNickname(userInfo.getNickname());
                listResp.setAvatar(userInfo.getAvatar());
            }

        }
        return houseRespList;
    }

    /**
     * 浏览数和浏览人数都+1
     *
     * @param userId
     * @param houseId
     */
    public void incrViewCountAndUserCount(Long userId, Long houseId) {

        //浏览数+1
        houseInteractionPanelDao.incrActualViewCount(houseId);

        //浏览人数+1
        incrViewUserCount(userId, houseId);
    }

    /**
     * 浏览人数 +1
     *
     * @param userId
     * @param houseId
     */
    @RedisLock(key = CacheLockConstants.HousePrefix.INCR_VIEW_USER_COUNT)
    public void incrViewUserCount(Long userId, Long houseId) {

        //如果用户ID为空，说明是未登录的情况下查看房源详情的，此时浏览人数不能+1，因为无法知道当前用户是谁
        if (userId == null) {
            return;
        }
        Long id = userViewHouseRecordDao.selectIdByUserIdAndHouseId(userId, houseId);
        //不存在才+1, 存在说明当前用户已经浏览过了，不能重复+1
        if (id == null) {
            UserViewHouseRecord userViewHouseRecord = new UserViewHouseRecord();
            userViewHouseRecord.setUserId(userId);
            userViewHouseRecord.setHouseId(houseId);
            userViewHouseRecordDao.insert(userViewHouseRecord);
            houseInteractionPanelDao.incrActualLikeCount(houseId);
        }
    }

}
